home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume2 / unix / shell211.1 < prev    next >
Text File  |  1988-10-25  |  60KB  |  2,608 lines

  1. Path: xanth!nic.MR.NET!tank!mimsy!dftsrv!ames!mailrus!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v02i022:  shell - cshell-like command processor V2.11, Part01/02
  5. Message-ID: <9830@swan.ulowell.edu>
  6. Date: 25 Oct 88 01:46:07 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 2597
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: dillon@cory.berkeley.edu (Matt Dillon)
  12. Posting-number: Volume 2, Issue 22
  13. Archive-name: unix/shell211.1
  14.  
  15. # This is a shell archive.  Remove anything before this line
  16. # then unpack it by saving it in a file and typing "sh file"
  17. # (Files unpacked will be owned by you and have default permissions).
  18. # This archive contains the following files:
  19. #    examples.txt
  20. #    execom.c
  21. #    fexec1.c
  22. #    fexec2.asm
  23. #    globals.c
  24. #    hat.c
  25. #    main.c
  26. #    run.c
  27. #    set.c
  28. #    shell.h
  29. #    sort.c
  30. #    sub.c
  31. #    tags
  32. #
  33. if `test ! -s examples.txt`
  34. then
  35. echo "writing examples.txt"
  36. cat > examples.txt << '\Rogue\Monster\'
  37. EXAMPLE FILES
  38.  
  39. ------------------------------------------------------------------------
  40. EXAMPLE INTERNAL COMMAND OVERIDING
  41. ------------------------------------------------------------------------
  42.  
  43. #Make CD not only do it's normal function, but also a PWD.
  44.  
  45. alias cd "%var \\cd $var;pwd"
  46.  
  47. ------------------------------------------------------------------------
  48. .LOGIN
  49. ------------------------------------------------------------------------
  50.  
  51. echo "shells, Matt"
  52. alias l     "%var if $var;echo $var;else;echo *;endif"
  53. alias c     "echo ^l"
  54. alias cc    "cd ram:;assign c: cb:c"
  55. alias wb    "cd ram:;assign c: sys:c"
  56. alias ed    "run ED"
  57. set dest ram:a
  58. set temp ram:
  59. set ld cb:clib
  60. set incdir cb:include
  61. set libs +$ld/lc.lib
  62. set ops  ""
  63.  
  64.  
  65. ------------------------------------------------------------------------
  66. RAM.SH
  67. ------------------------------------------------------------------------
  68. cp c:run ram:; cp c:assign ram:; cp c:cp ram:; assign c: ram:
  69.  
  70.  
  71. ------------------------------------------------------------------------
  72. C1.SH
  73. ------------------------------------------------------------------------
  74. foreach y ( $_passed ) "echo $y;lc1 -o$temp -i$incdir/ -i$incdir/lattice/ $y";echo DONE
  75.  
  76.  
  77. ------------------------------------------------------------------------
  78. C2.SH
  79. ------------------------------------------------------------------------
  80. foreach y ( $_passed ) "echo $y;lc2 -s -v $temp$y";echo DONE
  81.  
  82.  
  83. ------------------------------------------------------------------------
  84. LD.SH
  85. ------------------------------------------------------------------------
  86. blink $ld/lstartup.obj+$_passed library $ld/lc.lib+$ld/amiga.lib $ops to $dest
  87.  
  88.  
  89. ------------------------------------------------------------------------
  90. LDALL.SH
  91. ------------------------------------------------------------------------
  92. set O "";foreach y ( *.o ) "set O $O+$y";strtail O + $O
  93. ld $O;unset O
  94.  
  95.  
  96. \Rogue\Monster\
  97. else
  98.   echo "will not over write examples.txt"
  99. fi
  100. if [ `wc -c examples.txt | awk '{printf $1}'` -ne 1870 ]
  101. then
  102. echo `wc -c examples.txt | awk '{print "Got " $1 ", Expected " 1870}'`
  103. fi
  104. if `test ! -s execom.c`
  105. then
  106. echo "writing execom.c"
  107. cat > execom.c << '\Rogue\Monster\'
  108.  
  109. /*
  110.  * EXECOM.C
  111.  *
  112.  * (c)1986 Matthew Dillon     9 October 1986
  113.  *
  114.  *    Handles command parsing.
  115.  *
  116.  *
  117.  */
  118.  
  119. #include "shell.h"
  120.  
  121. #define ST_COND   0x01
  122. #define ST_NAME   0x02
  123. #define ST_EXA      0x04        /*    exact match required    */
  124.  
  125.  
  126. struct COMMAND {
  127.     int (*func)();
  128.     short minargs;
  129.     short stat;
  130.     int   val;
  131.     char *name;
  132. };
  133.  
  134. extern char *format_insert_string();
  135. extern char *mpush(), *exarg();
  136.  
  137. extern int do_run(), do_number();
  138. extern int do_quit(), do_set_var(), do_unset_var(), do_setenv(), do_unsetenv();
  139. extern int do_printenv(), do_echo(), do_source(), do_mv();
  140. extern int do_cd(), do_rm(), do_mkdir(), do_history();
  141. extern int do_mem(), do_cat(), do_dir();
  142. extern int do_foreach(), do_return(), do_if(), do_label(), do_goto();
  143. extern int do_forever(), do_inc(), do_abortline();
  144. extern int do_input(), do_ver(), do_sleep(), do_help();
  145. extern int do_strhead(), do_strtail(), do_cp();
  146. extern int do_comment(), do_shellstat(), do_ipc(), do_cldres();
  147.  
  148. static struct COMMAND Command[] = {
  149.     do_run    , 0,  ST_NAME,      0 ,    "\001",
  150.     do_number    , 0,  0,      0 ,    "\001",
  151.     do_quit    , 0,  ST_EXA,      0 ,    "quit",
  152.     do_quit    , 0,  ST_EXA,      0 ,    "exit",
  153.     do_set_var    , 0,  0, LEVEL_SET  ,    "set",
  154.     do_unset_var, 0,  0, LEVEL_SET  ,    "unset",
  155.     do_setenv    , 2,  0,      0 ,    "setenv",
  156.     do_unsetenv , 0,  0,      0 ,    "unsetenv",
  157.     do_printenv , 0,  0,      0 ,    "printenv",
  158.     do_set_var    , 0,  0, LEVEL_ALIAS,    "alias",
  159.     do_unset_var, 0,  0, LEVEL_ALIAS,    "unalias",
  160.     do_echo    , 0,  0,      0 ,    "echo",
  161.     do_source    , 0,  0,      0 ,    "source",
  162.     do_mv    , 2,  ST_EXA,      0 ,    "mv",
  163.     do_cd    , 0,  0,      0 ,    "cd",
  164.     do_cd    , 0,  0,     -1 ,    "pwd",
  165.     do_rm    , 0,  ST_EXA,      0 ,    "rm",
  166.     do_mkdir    , 0,  ST_EXA,      0 ,    "mkdir",
  167.     do_history    , 0,  0,      0 ,    "history",
  168.     do_mem    , 0,  0,      0 ,    "mem",
  169.     do_cat    , 0,  0,      0 ,    "cat",
  170.     do_cp    , 1,  ST_EXA,      0 ,    "cp",
  171.     do_dir    , 0,  0,      0 ,    "dir",
  172.     do_dir    , 0,  0,     -1 ,    "devinfo",
  173.     do_foreach    , 3,  0,      0 ,    "foreach",
  174.     do_forever    , 1,  0,      0 ,    "forever",
  175.     do_return    , 0,  ST_EXA,      0 ,    "return",
  176.     do_ipc    , 1,  0,      0 ,    "ipc",
  177.     do_cldres    , 0,  0,      0 ,    "cldres",
  178.     do_if    , 1,  ST_COND,      0 ,    "if",
  179.     do_if    , 0,  ST_COND,      1 ,    "else",
  180.     do_if    , 0,  ST_COND,      2 ,    "endif",
  181.     do_label    , 1,  ST_COND,      0 ,    "label",
  182.     do_goto    , 1,  0,      0 ,    "goto",
  183.     do_strhead    , 3,  0,      0 ,    "strhead",
  184.     do_strtail    , 3,  0,      0 ,    "strtail",
  185.     do_inc    , 1,  0,      1 ,    "inc",
  186.     do_inc    , 1,  0,      -1,    "dec",
  187.     do_input    , 1,  0,      0,    "input",
  188.     do_ver    , 0,  0,      0,    "version",
  189.     do_sleep    , 0,  0,      0,    "sleep",
  190.     do_help    , 0,  0,      0,    "help",
  191.     do_abortline, 0,  0,      0,    "abortline",
  192.     do_comment    , 2,  0,      0,    "comment",
  193.     do_shellstat, 0,  0,      0,    "shellstat",
  194.     NULL    , 0,  0,      0 ,    NULL
  195. };
  196.  
  197.  
  198. static unsigned char elast;         /* last end delimeter */
  199. static char Cin_ispipe, Cout_ispipe;
  200.  
  201. exec_command(base)
  202. char *base;
  203. {
  204.     register char *scr;
  205.     register int i;
  206.     char buf[32];
  207.  
  208.     if (!H_stack) {
  209.     add_history(base);
  210.     sprintf(buf, "%ld", H_tail_base + H_len);
  211.     set_var(LEVEL_SET, V_HISTNUM, buf);
  212.     }
  213.     scr = malloc((strlen(base) << 2) + 2);    /* 4X */
  214.     preformat(base, scr);
  215.     i = fcomm(scr, 1);
  216.     return ((i) ? -1 : 1);
  217. }
  218.  
  219.  
  220. isalphanum(c)
  221. char c;
  222. {
  223.     if (c >= '0' && c <= '9')
  224.     return (1);
  225.     if (c >= 'a' && c <= 'z')
  226.     return (1);
  227.     if (c >= 'A' && c <= 'Z')
  228.     return (1);
  229.     if (c == '_')
  230.     return (1);
  231.     return (0);
  232. }
  233.  
  234. preformat(s, d)
  235. register char *s, *d;
  236. {
  237.     register short si, di, qm;
  238.  
  239.     si = di = qm = 0;
  240.     while (s[si] == ' ' || s[si] == 9)
  241.     ++si;
  242.     while (s[si]) {
  243.     if (qm && s[si] != '\"' && s[si] != '\\') {
  244.         d[di++] = s[si++] | 0x80;
  245.         continue;
  246.     }
  247.     switch (s[si]) {
  248.     case ' ':
  249.     case 9:
  250.         d[di++] = ' ';
  251.         while (s[si] == ' ' || s[si] == 9)
  252.         ++si;
  253.         if (s[si] == 0 || s[si] == '|' || s[si] == ';')
  254.         --di;
  255.         break;
  256.     case '*':
  257.     case '?':
  258.         d[di++] = 0x80;     /* follow thru */
  259.     case '!':
  260.         d[di++] = s[si++];
  261.         break;
  262.     case '#':
  263.         d[di++] = '\0';
  264.         while (s[si])
  265.         ++si;
  266.         break;
  267.     case ';':
  268.     case '|':
  269.         d[di++] = s[si++];
  270.         while (s[si] == ' ' || s[si] == 9)
  271.         ++si;
  272.         break;
  273.     case '\\':
  274.         d[di++] = s[++si] | 0x80;
  275.         if (s[si]) ++si;
  276.         break;
  277.     case '\"':
  278.         qm = 1 - qm;
  279.         ++si;
  280.         break;
  281.     case '^':
  282.         d[di++] = s[++si] & 0x1F;
  283.         if (s[si]) ++si;
  284.         break;
  285.     case '$':         /* search end of var name and place false space */
  286.         d[di++] = 0x80;
  287.         d[di++] = s[si++];
  288.         while (isalphanum(s[si]))
  289.         d[di++] = s[si++];
  290.         d[di++] = 0x80;
  291.         break;
  292.     default:
  293.         d[di++] = s[si++];
  294.         break;
  295.     }
  296.     }
  297.     d[di++] = 0;
  298.     d[di]   = 0;
  299. #ifdef DEBUG
  300.     if (SDebug & 0x01) {
  301.     fhprintf (Cerr, "PREFORMAT: %ld :%s:\n", strlen(d), d);
  302.     }
  303. #endif
  304. }
  305.  
  306. /*
  307.  * process formatted string.  ' ' is the delimeter.
  308.  *
  309.  *    0: check '\0': no more, stop, done.
  310.  *    1: check $.     if so, extract, format, insert
  311.  *    2: check alias. if so, extract, format, insert. goto 1
  312.  *    3: check history or substitution, extract, format, insert. goto 1
  313.  *
  314.  *    4: assume first element now internal or disk based command.
  315.  *
  316.  *    5: extract each ' ' or 0x80 delimited argument and process, placing
  317.  *     in av[] list (except 0x80 args appended).  check in order:
  318.  *
  319.  *           '$'         insert string straight
  320.  *           '>'         setup stdout
  321.  *           '>>'        setup stdout flag for append
  322.  *           '<'         setup stdin
  323.  *           '*' or '?'  do directory search and insert as separate args.
  324.  *
  325.  *           ';' 0 '|'   end of command.  if '|' setup stdout
  326.  *                -execute command, fix stdin and out (|) sets
  327.  *                 up stdin for next guy.
  328.  */
  329.  
  330.  
  331. fcomm(str, freeok)
  332. register char *str;
  333. {
  334.     static short alias_count;
  335.     char *istr;
  336.     char *nextstr;
  337.     char *command;
  338.     char *pend_alias = NULL;
  339.     char err = 0;
  340.  
  341.     ++alias_count;
  342.     mpush_base();
  343.     if (*str == 0)
  344.     goto done1;
  345. step1:
  346.     if (alias_count == MAXALIAS) {
  347.     Eputs("Alias Loop");
  348.     err = 20;
  349.     goto done1;
  350.     }
  351.     if (*str == '$') {
  352.     if (istr = get_var (LEVEL_SET, str + 1))
  353.         str = format_insert_string(str, istr, &freeok);
  354.     }
  355.     istr = NULL;
  356.     if (*(unsigned char *)str < 0x80)
  357.     istr = get_var (LEVEL_ALIAS, str);  /* only if not \command */
  358.     *str &= 0x7F;               /* remove \ teltail       */
  359.     if (istr) {
  360.     if (*istr == '%') {
  361.         pend_alias = istr;
  362.     } else {
  363.         str = format_insert_string(str, istr, &freeok);
  364.         goto step1;
  365.     }
  366.     }
  367.     if (*str == '!') {
  368.     istr = get_history(str);
  369.     replace_head(istr);
  370.     str = format_insert_string(str, istr, &freeok);
  371.     goto step1;
  372.     }
  373.     nextstr = str;
  374.     command = exarg(&nextstr);
  375.     if (*command == 0)
  376.     goto done0;
  377.     if (pend_alias == 0) {
  378.     register int ccno;
  379.     ccno = find_command(command);
  380.     if (Command[ccno].stat & ST_COND)
  381.         goto skipgood;
  382.     }
  383.     if (SDisable) {
  384.     while (elast && elast != ';' && elast != '|')
  385.         exarg(&nextstr);
  386.     goto done0;
  387.     }
  388. skipgood:
  389.     {
  390.     register char *arg, *ptr, *scr;
  391.     short redir;
  392.     short doexpand;
  393.     short cont;
  394.     short inc;
  395.  
  396.     ac = 1;
  397.     av[0] = command;
  398. step5:                        /* ac = nextac */
  399.     if (!elast || elast == ';' || elast == '|')
  400.         goto stepdone;
  401.  
  402.     av[ac] = NULL;
  403.     cont = 1;
  404.     doexpand = redir = inc = 0;
  405.  
  406.     while (cont && elast) {
  407.         ptr = exarg(&nextstr);
  408.         inc = 1;
  409.         arg = "";
  410.         cont = (elast == 0x80);
  411.         switch (*ptr) {
  412.         case '<':
  413.         redir = -2;         /* -2 so ++ still keeps it negative */
  414.         case '>':
  415.         ++redir;         /* normal >  */
  416.         arg = ptr + 1;
  417.         if (*arg == '>') {
  418.             redir = 2;          /* append >> (not impl yet) */
  419.             ++arg;
  420.         }
  421.         cont = 1;
  422.         break;
  423.         case '$':
  424.         if ((arg = get_var(LEVEL_SET, ptr + 1)) == NULL)
  425.             arg = ptr;
  426.         break;
  427.          case '*':
  428.          case '?':
  429.         doexpand = 1;
  430.         arg = ptr;
  431.         break;
  432.         default:
  433.         arg = ptr;
  434.         break;
  435.         }
  436.  
  437.         /* Append arg to av[ac] */
  438.  
  439.         for (scr = arg; *scr; ++scr)
  440.         *scr &= 0x7F;
  441.         if (av[ac]) {
  442.         register char *old = av[ac];
  443.         av[ac] = mpush(strlen(arg)+1+strlen(av[ac]));
  444.         strcpy(av[ac], old);
  445.         strcat(av[ac], arg);
  446.         } else {
  447.         av[ac] = mpush(strlen(arg)+1);
  448.         strcpy(av[ac], arg);
  449.         }
  450.         if (elast != 0x80)
  451.         break;
  452.     }
  453.  
  454.     /* process expansion */
  455.  
  456.     if (doexpand) {
  457.         char **eav, **ebase;
  458.         int eac;
  459.  
  460.         eav = ebase = expand(av[ac], &eac);
  461.         inc = 0;
  462.         if (eav) {
  463.         if (ac + eac + 2 > MAXAV) {
  464.             ierror (NULL, 506);
  465.             err = 1;
  466.         } else {
  467.             QuickSort(eav, eac);
  468.             for (; eac; --eac, ++eav)
  469.             av[ac++] = strcpy(mpush(strlen(*eav)+1), *eav);
  470.         }
  471.         free_expand (ebase);
  472.         }
  473.     }
  474.  
  475.     /* process redirection    */
  476.  
  477.     if (redir && !err) {
  478.         register char *file = (doexpand) ? av[--ac] : av[ac];
  479.  
  480.         if (redir < 0) {
  481.         Cin_name = file;
  482.         } else {
  483.         Cout_name = file;
  484.         Cout_append = (redir == 2);
  485.         }
  486.         inc = 0;
  487.     }
  488.  
  489.     /* check elast for space */
  490.  
  491.     if (inc) {
  492.         ++ac;
  493.         if (ac + 2 > MAXAV) {
  494.         ierror (NULL, 506);
  495.         err = 1;        /* error condition */
  496.         elast = 0;        /* don't process any more arguemnts */
  497.         }
  498.     }
  499.     if (elast == ' ')
  500.         goto step5;
  501.     }
  502. stepdone:
  503.     av[ac] = NULL;
  504.  
  505.     /* process pipes via files */
  506.  
  507.     if (elast == '|' && !err) {
  508.     static int which;          /* 0 or 1 in case of multiple pipes */
  509.     which = 1 - which;
  510.     Cout_name = (which) ? Pipe1 : Pipe2;
  511.     Cout_ispipe = 1;
  512.     }
  513.  
  514.     if (err)
  515.     goto done0;
  516.  
  517.     {
  518.     register long i, len;
  519.     char save_elast;
  520.     register char *avline;
  521.  
  522.     save_elast = elast;
  523.     for (i = len = 0; i < ac; ++i)
  524.         len += strlen(av[i]) + 1;
  525.     avline = malloc(len+2);
  526.     for (len = 0, i = ((pend_alias) ? 1 : 0); i < ac; ++i) {
  527. #ifdef DEBUG
  528.         if (SDebug & 0x02) fhprintf (Cerr, "AV[%2ld] %ld :%s:\n", i, strlen(av[i]), av[i]);
  529. #endif
  530.         strcpy(avline + len, av[i]);
  531.         len += strlen(av[i]);
  532.         if (i + 1 < ac)
  533.         avline[len++] = ' ';
  534.     }
  535.     avline[len] = 0;
  536.     if (pend_alias) {                               /* special % alias */
  537.         register char *ptr, *scr;
  538.         for (ptr = pend_alias; *ptr && *ptr != ' '; ++ptr);
  539.         set_var (LEVEL_SET, pend_alias + 1, avline);
  540.         free (avline);
  541.         scr = malloc((strlen(ptr) << 2) + 2);
  542.         preformat (ptr, scr);
  543.         fcomm (scr, 1);
  544.         unset_var (LEVEL_SET, pend_alias + 1);
  545.     } else {                    /* normal command  */
  546.         register short ccno;
  547.         register long cin, cout;
  548.  
  549.         ccno = find_command (command);
  550.         if ((Command[ccno].stat & ST_NAME) == 0) {
  551.         if (Cin_name) {
  552.             cin = Cin;
  553.             Cin = Open(Cin_name, 1005);
  554.             if (Cin == 0) {
  555.             ierror (NULL, 504);
  556.             err = 1;
  557.             Cin = cin;
  558.             Cin_name = NULL;
  559.             }
  560.         }
  561.         if (Cout_name) {
  562.             cout = Cout;
  563.             if (Cout_append) {
  564.             if (Cout = Open(Cout_name, 1005))
  565.             Seek(Cout, 0, 1);
  566.             } else {
  567.             Cout = Open(Cout_name, 1006);
  568.             }
  569.             if (Cout == NULL) {
  570.             err = 1;
  571.             ierror (NULL, 504);
  572.             Cout = cout;
  573.             Cout_name = NULL;
  574.             Cout_append = 0;
  575.             }
  576.         }
  577.         }
  578.         if (ac < Command[ccno].minargs + 1) {
  579.         ierror (NULL, 500);
  580.         err = -1;
  581.         } else {
  582.         i = (*Command[ccno].func)(avline, Command[ccno].val);
  583.         if (i < 0)
  584.             i = 20;
  585.         err = i;
  586.         }
  587.         free (avline);
  588.         if (Exec_ignoreresult == 0 && Lastresult != err) {
  589.         Lastresult = err;
  590.         seterr();
  591.         }
  592.         if ((Command[ccno].stat & ST_NAME) == 0) {
  593.         if (Cin_name) {
  594.             Close(Cin);
  595.             Cin = cin;
  596.         }
  597.         if (Cout_name) {
  598.             Close(Cout);
  599.             Cout = cout;
  600.             Cout_append = 0;
  601.         }
  602.         }
  603.     }
  604.     if (Cin_ispipe && Cin_name)
  605.         DeleteFile(Cin_name);
  606.     if (Cout_ispipe) {
  607.         Cin_name = Cout_name;      /* ok to assign.. static name */
  608.         Cin_ispipe = 1;
  609.     } else {
  610.         Cin_name = NULL;
  611.     }
  612.     Cout_name = NULL;
  613.     Cout_ispipe = Cout_append = 0;
  614.     elast = save_elast;
  615.     }
  616.     mpop_tobase();                      /* free arguments   */
  617.     mpush_base();                       /* push dummy base  */
  618.  
  619. done0:
  620.     {
  621.     register char *str;
  622. #ifdef DEBUG
  623.     if (SDebug & 0x10)
  624.         printf ("err = %ld, E_stack = %ld\n", err, E_stack);
  625. #endif
  626.     if (err && E_stack == 0) {
  627.         str = get_var(LEVEL_SET, V_EXCEPT);
  628.         if (err >= ((str)?atoi(str):1)) {
  629.         if (str) {
  630.             ++H_stack;
  631.             ++E_stack;
  632.             exec_command(str);
  633.             --E_stack;
  634.             --H_stack;
  635.         } else {
  636.           Exec_abortline = 1;
  637.         }
  638.         }
  639.     }
  640. #ifdef DEBUG
  641.     if (SDebug & 0x10) {
  642.         printf ("elast = %ld  Exec_abortline = %ld\n", elast, Exec_abortline);
  643.         printf ("nextstr = %s\n", nextstr);
  644.     }
  645. #endif
  646.     if (elast != 0 && Exec_abortline == 0)
  647.         err = fcomm(nextstr, 0);
  648.     Exec_abortline = 0;
  649.     if (Cin_name)
  650.         DeleteFile(Cin_name);
  651.     Cin_name = NULL;
  652.     Cin_ispipe = 0;
  653.     }
  654. done1:
  655.     mpop_tobase();
  656.     if (freeok)
  657.     free(str);
  658.     --alias_count;
  659.     return ((int)err);                  /* TRUE = error occured    */
  660. }
  661.  
  662.  
  663. char *
  664. exarg(ptr)
  665. unsigned char **ptr;
  666. {
  667.     register unsigned char *end;
  668.     register unsigned char *start;
  669.  
  670.     start = end = *ptr;
  671.     while (*end && *end != 0x80 && *end != ';' && *end != '|' && *end != ' ')
  672.     ++end;
  673.     elast = *end;
  674.     *end = '\0';
  675.     *ptr = end + 1;
  676.     return ((char *)start);
  677. }
  678.  
  679. static char **Mlist;
  680.  
  681. mpush_base()
  682. {
  683.     register char *str;
  684.  
  685.     str = malloc(5);
  686.     *(char ***)str = Mlist;
  687.     str[4] = 0;
  688.     Mlist = (char **)str;
  689. }
  690.  
  691. char *
  692. mpush(bytes)
  693. {
  694.     register char *str;
  695.  
  696.     str = malloc(5 + bytes);
  697.     *(char ***)str = Mlist;
  698.     str[4] = 1;
  699.     Mlist = (char **)str;
  700.     return (str + 5);
  701. }
  702.  
  703. mpop_tobase()
  704. {
  705.     register char *next;
  706.  
  707.     while (Mlist) {
  708.     next = *Mlist;
  709.     if (((char *)Mlist)[4] == 0) {
  710.         free (Mlist);
  711.         Mlist = (char **)next;
  712.         break;
  713.     }
  714.     free (Mlist);
  715.     Mlist = (char **)next;
  716.     }
  717. }
  718.  
  719.  
  720. /*
  721.  * Insert 'from' string in front of 'str' while deleting the
  722.  * first entry in 'str'.  if freeok is set, then 'str' will be
  723.  * free'd
  724.  */
  725.  
  726. char *
  727. format_insert_string(str, from, freeok)
  728. char *str;
  729. char *from;
  730. int *freeok;
  731. {
  732.     register char *new1, *new2;
  733.     register unsigned char *strskip;
  734.     register short len;
  735.  
  736.     for (strskip = (UBYTE *)str; *strskip && *strskip != ' ' && *strskip != ';' && *strskip != '|' && *strskip != 0x80; ++strskip);
  737.     len = strlen(from);
  738.     new1 = malloc((len << 2) + 2);
  739.     preformat(from, new1);
  740.     len = strlen(new1) + strlen(strskip);
  741.     new2 = malloc(len+2);
  742.     strcpy(new2, new1);
  743.     strcat(new2, strskip);
  744.     new2[len+1] = 0;
  745.     free (new1);
  746.     if (*freeok)
  747.     free (str);
  748.     *freeok = 1;
  749.     return (new2);
  750. }
  751.  
  752.  
  753. find_command(str)
  754. register char *str;
  755. {
  756.     register short i;
  757.     register short len = strlen(str);
  758.     register struct COMMAND *cmd;
  759.  
  760.     if (*str >= '0'  &&  *str <= '9')
  761.     return (1);
  762.     for (i = 0, cmd = Command; cmd->func; ++cmd, ++i) {
  763.     if (cmd->stat & ST_EXA) {
  764.         if (strcmp(str, cmd->name) == 0)
  765.         return((int)i);
  766.     } else {
  767.         if (strncmp (str, cmd->name, len) == 0)
  768.         return ((int)i);
  769.     }
  770.     }
  771.     return (0);
  772. }
  773.  
  774.  
  775. do_help()
  776. {
  777.     register struct COMMAND *com;
  778.  
  779.     for (com = &Command[2]; com->func; ++com)
  780.     fhprintf (Cout, "%s ", com->name);
  781.     Oputs ("");
  782.     return (0);
  783. }
  784.  
  785.  
  786. \Rogue\Monster\
  787. else
  788.   echo "will not over write execom.c"
  789. fi
  790. if [ `wc -c execom.c | awk '{printf $1}'` -ne 14743 ]
  791. then
  792. echo `wc -c execom.c | awk '{print "Got " $1 ", Expected " 14743}'`
  793. fi
  794. if `test ! -s fexec1.c`
  795. then
  796. echo "writing fexec1.c"
  797. cat > fexec1.c << '\Rogue\Monster\'
  798.  
  799. /*
  800.  * FEXEC1.C
  801.  *
  802.  *  (C)CopyRight 1987 Matthew Dillon, All rights reserved.
  803.  *
  804.  *    wait() and fexecv()
  805.  *
  806.  *    This code originated from Manx's fexecv code.  I claim credit only
  807.  *    for the major modifications I've done to it.
  808.  */
  809.  
  810. #include "shell.h"
  811. #include <libraries/dosextens.h>
  812.  
  813. typedef struct CommandLineInterface CLI;
  814. typedef struct FileHandle FH;
  815.  
  816. static int ret_val;
  817.  
  818. wait()
  819. {
  820.     return(ret_val);
  821. }
  822.  
  823.  
  824. fexecv(cmd, argv, stdin_str, stdout_str, stdout_append)
  825. char *cmd, **argv;
  826. char *stdin_str, *stdout_str;
  827. {
  828.     register CLI *cli;
  829.     register char **ap, *cp, *arg;
  830.     PROC *pp;
  831.     APTR sav_ret;
  832.     BPTR sav_CIS, sav_COS;
  833.     long save_stdin_buf, save_stdin_pos, save_stdin_end;
  834.     long len, seg, sav_seg;
  835.     long openmode;
  836.     long *stk;
  837.     FH *fhp, *stdin, *stdout;
  838.     char buf[40];
  839.  
  840.     pp = FindTask(0L);
  841.     if ((cli = (CLI *)((long)pp->pr_CLI << 2)) == 0)
  842.     return(-1);
  843.     if ((seg = LoadIt(cmd)) == 0)
  844.     return(-3);
  845.     stdin = (FH *)((stdin_str)? Open(stdin_str, 1005) : pp->pr_CIS);
  846.     if (!stdin) {
  847.     fhprintf(Cerr, "Input redirection error\n");
  848.     return(-4);
  849.     }
  850.     openmode = (stdout_append) ? 1005 : 1006;
  851.     stdout= (FH *)((stdout_str)? Open(stdout_str, openmode) : pp->pr_COS);
  852.     if (!stdout) {
  853.     fhprintf(Cerr, "Output redirection error\n");
  854.     if (stdin_str)
  855.         Close(stdin);
  856.     return(-5);
  857.     }
  858.     if (stdout_append)
  859.     Seek(stdout, 0, 1);
  860.     sav_seg = cli->cli_Module;
  861.     cli->cli_Module = seg;
  862.     stk = (long *)AllocMem(4 * cli->cli_DefaultStack + 8, 0);
  863.     *stk = 4 * cli->cli_DefaultStack + 8;
  864.     stk = (long *)((long)stk + 4 * cli->cli_DefaultStack);
  865.     stk[0] = 4 * cli->cli_DefaultStack;
  866.     stk[1] = ((long *)pp->pr_ReturnAddr)[1];
  867.     sav_ret = pp->pr_ReturnAddr;
  868.     pp->pr_ReturnAddr = (APTR)stk;
  869.  
  870.     for (len = 1, ap = argv + 1; *ap; ++ap)  /* length of command line */
  871.     len += strlen(*ap) + 1;
  872.     cp = arg = malloc(len + 1);
  873.     for (ap = argv + 1; *ap; ++ap) {
  874.     strcpy(cp, *ap);
  875.     strcat(cp, " ");
  876.     cp += strlen(cp);
  877.     }
  878.     if (len > 199)                           /* BCPL parameter limit   */
  879.     len = 199;
  880.     arg[len-1] = '\n';                       /* for BCPL               */
  881.     arg[len]   = 0;                 /* for C               */
  882.     cp = (char *)((long)cli->cli_CommandName << 2);
  883.     movmem(cp, buf, 40);
  884.     strcpy(cp + 1, cmd);
  885.     cp[0] = strlen(cmd);
  886.  
  887.     fhp = (FH *)((long)stdin << 2);
  888.     save_stdin_buf = fhp->fh_Buf;
  889.     save_stdin_pos = fhp->fh_Pos;
  890.     save_stdin_end = fhp->fh_End;
  891.  
  892.     fhp->fh_Buf = (long)AllocMem(202, 0) >> 2;
  893.     bmov(arg, fhp->fh_Buf<<2, len);
  894.     fhp->fh_Pos = 0;
  895.     fhp->fh_End = len;
  896.  
  897.     sav_CIS = pp->pr_CIS;
  898.     sav_COS = pp->pr_COS;
  899.  
  900.     pp->pr_CIS = (BPTR)stdin;
  901.     pp->pr_COS = (BPTR)stdout;
  902.  
  903.     /*
  904.      *    pr_Result2 must be NULL or RUN/NEWCLI think the command line is
  905.      *    somewhere other than in the file handle.  The cli_Interactive
  906.      *    field gets cleared sometimes (how???), and for some reason, signal
  907.      *    31 is set sometimes and might cause inproper operation of RUN.
  908.      */
  909.  
  910.     pp->pr_Result2 = NULL;
  911.     cli->cli_Interactive = -1;
  912.     SetSignal(0L, 0x80000000);
  913.  
  914.     ret_val = doexec(len, arg, (seg+1)<<2, stk);
  915.  
  916.     FreeMem(fhp->fh_Buf<<2, 202);
  917.     fhp->fh_Buf = save_stdin_buf;
  918.     fhp->fh_Pos = save_stdin_pos;
  919.     fhp->fh_End = save_stdin_end;
  920.  
  921.     if (stdin_str)
  922.     Close(stdin);
  923.     if (stdout_str)
  924.     Close(stdout);
  925.     pp->pr_CIS = sav_CIS;
  926.     pp->pr_COS = sav_COS;
  927.  
  928.     UnLoadSeg(cli->cli_Module);
  929.     pp->pr_ReturnAddr = sav_ret;
  930.     cli->cli_Module = sav_seg;
  931.     free(arg);
  932.     movmem(buf, cp, 40);
  933.     return(0);
  934. }
  935.  
  936. LoadIt(cmd)
  937. char *cmd;
  938. {
  939.     long seg;
  940.  
  941.     mountrequest(0);
  942.     if ((seg = LoadSeg(cmd)) == NULL) {
  943.     register long lock;
  944.     char buf[128];
  945.  
  946.     if (lock = FindIt(cmd, "", buf)) {
  947.         register long pardir = ParentDir(lock);
  948.         if (pardir) {
  949.         register long oldir = CurrentDir(pardir);
  950.         seg = LoadSeg(cmd);
  951.         CurrentDir(oldir);
  952.         UnLock(pardir);
  953.         }
  954.         UnLock(lock);
  955.     }
  956.     }
  957.     mountrequest(1);
  958.     return(seg);
  959. }
  960.  
  961. /*
  962.  *  Find a specific command (cmd) with extension (ext).  Returns
  963.  *  a lock if found, else NULL.  Searches both the symbolic path and
  964.  *  the CLI path.  The symbolic path is searched first.
  965.  */
  966.  
  967. long
  968. FindIt(cmd, ext, buf)
  969. char *cmd;
  970. char *ext;
  971. char *buf;
  972. {
  973.     register long lock = 0;
  974.     register char *p;
  975.     PROC *myproc = FindTask(0);
  976.  
  977.     strcpy(buf, cmd);
  978.     strcat(buf, ext);
  979.     if (rindex(buf, ':') || rindex(buf, '/'))
  980.     return(Lock(buf, ACCESS_READ));
  981.  
  982.     if ((p = get_var(LEVEL_SET, V_PATH)) == NULL)
  983.     p = "";
  984.  
  985. #ifdef DEBUG
  986.     if (SDebug)
  987.     printf ("FindIt: try: %s\n", buf);
  988. #endif
  989.     while ((lock = Lock(buf, ACCESS_READ)) == 0 || !isfile(lock)) {
  990.     register short n;
  991.     if (lock)
  992.         UnLock(lock);
  993.     if (*p == '\0') {
  994.         buf[0] = 0;
  995.         break;
  996.     }
  997.     for (n = 0; p[n] && p[n] != ','; ++n);
  998.     strncpy(buf, p, n);
  999.     buf[n] = 0;
  1000.     strcat(buf, cmd);
  1001.     strcat(buf, ext);
  1002.     p += n + (*p != 0);
  1003. #ifdef DEBUG
  1004.     if (SDebug)
  1005.         printf ("FindIt: try: %s\n", buf);
  1006. #endif
  1007.     }
  1008. #ifdef DEBUG
  1009.     if (SDebug)
  1010.     puts ("FindIt 1");
  1011. #endif
  1012.     if (lock)
  1013.     return(lock);
  1014.  
  1015.     /*
  1016.      *    Search the CLI path by CurrentDir'ing each lock and
  1017.      *    attempting to lock the name
  1018.      */
  1019.  
  1020. #ifdef DEBUG
  1021.     if (SDebug)
  1022.     puts("SEARCH CLI");
  1023. #endif
  1024.  
  1025.     strcpy(buf, cmd);
  1026.     strcat(buf, ext);
  1027.     if (myproc->pr_CLI) {
  1028.     long oldir;
  1029.     long dupdir;
  1030.     register LOCK *dirlock = (LOCK *)(((CLI *)(myproc->pr_CLI << 2))->cli_CommandDir << 2);
  1031.     for (; dirlock; dirlock = (LOCK *)(dirlock->fl_Link << 2)) {
  1032.         oldir = CurrentDir(((long *)dirlock)[1]);
  1033.         lock = Lock(buf, ACCESS_READ);
  1034.         CurrentDir(oldir);
  1035.         if (lock)
  1036.         break;
  1037.     }
  1038.     }
  1039.  
  1040. #ifdef DEBUG
  1041.     if (SDebug)
  1042.     puts("FindIt done");
  1043. #endif
  1044.     return(lock);
  1045. }
  1046.  
  1047. static
  1048. isfile(lock)
  1049. long lock;
  1050. {
  1051.     register FIB *fib = (FIB *)malloc(sizeof(FIB));
  1052.     register int result = 0;
  1053.  
  1054.     if (fib) {
  1055.     if (Examine(lock, fib))
  1056.         result = fib->fib_DirEntryType;
  1057.     free(fib);
  1058.     }
  1059.     return(result < 0);         /*  is it a file?   */
  1060. }
  1061.  
  1062. \Rogue\Monster\
  1063. else
  1064.   echo "will not over write fexec1.c"
  1065. fi
  1066. if [ `wc -c fexec1.c | awk '{printf $1}'` -ne 5948 ]
  1067. then
  1068. echo `wc -c fexec1.c | awk '{print "Got " $1 ", Expected " 5948}'`
  1069. fi
  1070. if `test ! -s fexec2.asm`
  1071. then
  1072. echo "writing fexec2.asm"
  1073. cat > fexec2.asm << '\Rogue\Monster\'
  1074.  
  1075. ;FEXEC2.ASM
  1076. ;
  1077.  
  1078. ;  Again, this code originated from Manx, but has been heavily re-written
  1079. ;
  1080.  
  1081.       xdef  _doexec
  1082.       xref  _LVOFreeMem
  1083.       xref  _SysRegs
  1084.       xref  _SysBase
  1085.       xref  _savsp
  1086.       xref  _savefp
  1087.  
  1088.  
  1089. ;
  1090. ;doexec(len, arg, (seg+1)<<2, stk)
  1091. ;       D0    A0    A4        A7
  1092. ;
  1093.  
  1094.         FAR data                ;because we totally trash A4 within the
  1095.         FAR code                ;routine.
  1096.  
  1097. _doexec:
  1098.    move.l   sp,_savefp            ;Save Frame Pointer
  1099.    movem.l  d2-d7/a2-a6,-(sp)    ;save Registers
  1100.    move.l   sp,_savsp             ;save current SP
  1101.    lea     _SysRegs,A0
  1102.    movem.l  (A0),D0-D7/A0-A6     ;Get System Startup Registers (BCPL stuff)
  1103.    move.l   _savefp,A0            ;A0 = frame pointer
  1104.    movem.l  4(A0),d0/a0/a4/a7    ;load parameters, including new SP
  1105.    move.l   d0,12(a1)            ;set length
  1106.    move.l   a0,d1                ;copy to dreg
  1107.    lsr.l    #2,d1                ;convert to BPTR
  1108.    move.l   d1,8(a1)             ;set ptr
  1109.    jsr      (a4)                 ;call new program
  1110.    movem.l  (sp)+,d2/d3          ;get stk siz and old sp
  1111.    move.l   sp,a1                ;save current sp
  1112.    move.l   _savsp,sp             ;get back our sp
  1113.    move.l   d0,-(sp)             ;save return code so we don't loose it
  1114.    sub.l    d2,a1                ;Backup from end of stack to start
  1115.    sub.l    #8,a1                ;point over header placed on stack
  1116.    move.l   (a1),d0              ;get size to free
  1117.    move.l   _SysBase,a6          ;get ExecBase
  1118.    jsr      _LVOFreeMem(a6)      ;Free memory allocated for stack
  1119.    move.l   (sp)+,d0             ;D0 = return code
  1120.    movem.l  (sp)+,D2-D7/A2-A6    ;restore Registers
  1121.    rts
  1122.  
  1123.  
  1124.  
  1125. \Rogue\Monster\
  1126. else
  1127.   echo "will not over write fexec2.asm"
  1128. fi
  1129. if [ `wc -c fexec2.asm | awk '{printf $1}'` -ne 1670 ]
  1130. then
  1131. echo `wc -c fexec2.asm | awk '{print "Got " $1 ", Expected " 1670}'`
  1132. fi
  1133. if `test ! -s globals.c`
  1134. then
  1135. echo "writing globals.c"
  1136. cat > globals.c << '\Rogue\Monster\'
  1137.  
  1138. /*
  1139.  * GLOBALS.C
  1140.  *
  1141.  * (c)1986 Matthew Dillon     9 October 1986
  1142.  *
  1143.  *
  1144.  *    Most global variables.
  1145.  *
  1146.  */
  1147.  
  1148. #include "shell.h"
  1149.  
  1150. struct HIST *H_head, *H_tail;            /* HISTORY lists      */
  1151.  
  1152. struct PERROR Perror[] = {            /* error code->string */
  1153.     103,  "insufficient free storage",
  1154.     105,  "task table full",
  1155.     120,  "argument line invalid or too long",
  1156.     121,  "file is not an object module",
  1157.     122,  "invalid resident library during load",
  1158.     201,  "no default directory",
  1159.     202,  "object in use",
  1160.     203,  "object already exists",
  1161.     204,  "directory not found",
  1162.     205,  "object not found",
  1163.     206,  "bad stream name",
  1164.     207,  "object too large",
  1165.     209,  "action not known",
  1166.     210,  "invalid stream component name",
  1167.     211,  "invalid object lock",
  1168.     212,  "object not of required type",
  1169.     213,  "disk not validated",
  1170.     214,  "disk write protected",
  1171.     215,  "rename across devices",
  1172.     216,  "directory not empty",
  1173.     217,  "too many levels",
  1174.     218,  "device not mounted",
  1175.     219,  "seek error",
  1176.     220,  "comment too long",
  1177.     221,  "disk full",
  1178.     222,  "file delete protected",
  1179.     223,  "file write protected",
  1180.     224,  "file read protected",
  1181.     225,  "not a DOS disk",
  1182.     226,  "no disk",
  1183.     232,  "no more entries in directory",
  1184.  
  1185.     /* custom error messages */
  1186.  
  1187.     500,  "bad arguments",
  1188.     501,  "label not found",
  1189.     502,  "must be within source file",
  1190.     503,  "Syntax Error",
  1191.     504,  "redirection error",
  1192.     505,  "pipe error",
  1193.     506,  "too many arguments",
  1194.     507,  "destination not a directory",
  1195.     508,  "cannot mv a filesystem",
  1196.     509,  "Operation Aborted",
  1197.     510,  "Too many if's",
  1198.       0,  NULL
  1199. };
  1200.  
  1201. char  *av[MAXAV];        /* Internal argument list              */
  1202. int   Src_base[MAXSRC];     /* file pointers for source files          */
  1203. long  Src_pos[MAXSRC];        /* seek position storage for same          */
  1204. char  If_base[MAXIF];        /* If/Else stack for conditionals          */
  1205. short H_len, H_tail_base;   /* History associated stuff           */
  1206. short H_stack;            /* AddHistory disable stack           */
  1207. short E_stack;            /* Exception disable stack              */
  1208. short Src_stack, If_stack;  /* Stack Indexes                  */
  1209. short ac;            /* Internal argc                  */
  1210. short SDebug;            /* Debug mode                  */
  1211. short SDisable;         /* Disable com. execution (conditionals)  */
  1212. short Verbose;            /* Verbose mode for source files          */
  1213. long  Lastresult;        /* Last return code               */
  1214. short Exec_abortline;        /* flag to abort rest of line          */
  1215. short Exec_ignoreresult;    /* flag to ignore result              */
  1216. short Quit;            /* Quit flag                  */
  1217. long  Cout, Cin, Cerr;        /* Current input and output file handles  */
  1218. long  Cout_append;        /* append flag for Cout              */
  1219. long  Uniq;            /* unique value                  */
  1220. char  *Cin_name, *Cout_name;/* redirection input/output name or NULL  */
  1221. char  *Pipe1, *Pipe2;        /* the two pipe temp. files           */
  1222.  
  1223. short S_histlen = 20;        /* Max # history entries              */
  1224. short S_ignoreeof;
  1225.  
  1226. long SysRegs[16] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 };
  1227. long savsp, savefp;
  1228.  
  1229.  
  1230. \Rogue\Monster\
  1231. else
  1232.   echo "will not over write globals.c"
  1233. fi
  1234. if [ `wc -c globals.c | awk '{printf $1}'` -ne 3086 ]
  1235. then
  1236. echo `wc -c globals.c | awk '{print "Got " $1 ", Expected " 3086}'`
  1237. fi
  1238. if `test ! -s hat.c`
  1239. then
  1240. echo "writing hat.c"
  1241. cat > hat.c << '\Rogue\Monster\'
  1242.  
  1243. /*
  1244.  *    HAT.C
  1245.  *
  1246.  *    Modify the last history entry ^search^replace.  Called from
  1247.  *    MAIN.C
  1248.  *
  1249.  */
  1250.  
  1251. extern char *last_history_entry();
  1252.  
  1253. hat_replace(buf)
  1254. char *buf;
  1255. {
  1256.     char res[256];
  1257.     char *ptr, *hb, *repstr, *srchstr;
  1258.     int searchlen, replacelen;
  1259.  
  1260.     srchstr = buf + 1;
  1261.     for (repstr = srchstr; *repstr && *repstr != '^'; ++repstr);
  1262.     if (*repstr) {
  1263.     searchlen = repstr - srchstr;
  1264.     *repstr = '\0';
  1265.     ++repstr;
  1266.     }
  1267.     replacelen = strlen(repstr);
  1268.  
  1269.     for (ptr = hb = last_history_entry(); *ptr; ++ptr) {
  1270.     if (strncmp(ptr, srchstr, searchlen) == 0) {
  1271.         bmov(hb, res, ptr - hb);         /* first part of history    */
  1272.         res[ptr-hb] = '\0';              /* add 0                   */
  1273.         strcat(res, repstr);         /* add replace string    */
  1274.         strcat(res, ptr+searchlen);      /* add rest of history    */
  1275.         strcpy(buf, res);             /* copy            */
  1276.         puts (buf);
  1277.         return(1);                 /* done            */
  1278.     }
  1279.     }
  1280.     puts ("modifier failed");
  1281.     *buf = '\0';
  1282.     return(0);
  1283. }
  1284.  
  1285.  
  1286. \Rogue\Monster\
  1287. else
  1288.   echo "will not over write hat.c"
  1289. fi
  1290. if [ `wc -c hat.c | awk '{printf $1}'` -ne 992 ]
  1291. then
  1292. echo `wc -c hat.c | awk '{print "Got " $1 ", Expected " 992}'`
  1293. fi
  1294. if `test ! -s main.c`
  1295. then
  1296. echo "writing main.c"
  1297. cat > main.c << '\Rogue\Monster\'
  1298.  
  1299. /*
  1300.  * MAIN.C
  1301.  *
  1302.  *  (C)Copyright 1987 Matthew Dillon, All rights reserved
  1303.  *
  1304.  *  Contains initialization and other stuff.  Note that there is no
  1305.  *  support for workbench startup.  This isn't simply a matter of
  1306.  *  setting up a window.... to get this baby to work from workbench we
  1307.  *  would need to simulate an entire CLI (proc->pr_CLI must be valid).
  1308.  *
  1309.  */
  1310.  
  1311. #include "shell.h"
  1312. #include <libraries/dosextens.h>
  1313. #include <stdio.h>
  1314.  
  1315. extern long SetSignal();
  1316.  
  1317. char Inline[256];
  1318. static long Orig_dir;
  1319.  
  1320. extern int Enable_Abort;
  1321.  
  1322. main(argc, argv)
  1323. short argc;
  1324. register char *argv[];
  1325. {
  1326.     char *prompt;
  1327.     struct Process *proc;
  1328.     register short i;
  1329.  
  1330.     Enable_Abort = 0;
  1331.     proc = (PROC *)FindTask(0);
  1332.     if (proc->pr_CLI == NULL)              /* sorry, no WB startup */
  1333.     exit(1000);
  1334.     Orig_dir = proc->pr_CurrentDir;
  1335.     CurrentDir(DupLock(Orig_dir));
  1336.     init_vars();
  1337.     init();
  1338.     seterr();
  1339.     do_cd(NULL, -1);
  1340.     for (i = 1; i < argc; ++i) {
  1341.     if (strcmp(argv[i], "-c") == 0) {
  1342.         Inline[0] = '\0';
  1343.         for (++i; i < argc; ++i) {
  1344.         if (*argv[i] == '\"') {             /* CLI quotes?   */
  1345.             strcat(Inline, argv[i]+1);       /* remove quotes */
  1346.             Inline[strlen(Inline)-1] = '\0';
  1347.         } else {
  1348.             strcat(Inline, argv[i]);
  1349.         }
  1350.         if (i + 1 < argc)
  1351.             strcat(Inline, " ");
  1352.         }
  1353.         exec_command(Inline);
  1354.         main_exit(0);
  1355.     }
  1356.     strcpy (Inline, "source ");
  1357.     strcat (Inline, argv[i]);
  1358.     av[0] = "source";
  1359.     av[1] = argv[i];
  1360.     do_source (Inline, 0);
  1361.     }
  1362.     for (;;) {
  1363.     if ((prompt = get_var (LEVEL_SET, V_PROMPT)) == NULL)
  1364.         prompt = "echo -n \"% \"";
  1365.     /*
  1366.      *
  1367.      *  Removed, WaitForChar() is buggy
  1368.      *
  1369.     if (CHECKBREAK()) {
  1370.         while (WaitForChar(Input(), 10))
  1371.         gets(Inline);
  1372.     }
  1373.      */
  1374.  
  1375.     ++H_stack;
  1376.     ++Exec_ignoreresult;
  1377.     exec_command (prompt);
  1378.     --Exec_ignoreresult;
  1379.     --H_stack;
  1380.     if (Quit)
  1381.         main_exit(0);
  1382.     if (gets(Inline) == NULL) {
  1383.         if (IsInteractive(Input()) && !S_ignoreeof)
  1384.         main_exit(0);
  1385.         clearerr(stdin);
  1386.     }
  1387.     resetbreak();
  1388.     if (*Inline == '^')
  1389.         hat_replace(Inline);
  1390.     if (*Inline)
  1391.         exec_command(Inline);
  1392.     }
  1393. }
  1394.  
  1395. init_vars()
  1396. {
  1397.     if (IsInteractive(Input()))
  1398.     set_var (LEVEL_SET, V_PROMPT, "echo -n \"% \"");
  1399.     else
  1400.     set_var (LEVEL_SET, V_PROMPT, "");
  1401.     set_var (LEVEL_SET, V_HIST, "20");
  1402.     set_var (LEVEL_SET, V_PATH, "ram:,ram:c/,c:,df2:c/,df1:c/,df0:c/");
  1403. }
  1404.  
  1405. init()
  1406. {
  1407.     static char pipe1[32], pipe2[32];
  1408.  
  1409.     Cin = Input();
  1410.     Cout= Cerr = Output();
  1411.     Uniq= (long)pipe1;         /* address of some global variable */
  1412.     Pipe1 = pipe1;
  1413.     Pipe2 = pipe2;
  1414.     sprintf (pipe1, "ram:pipe1_%ld", Uniq);
  1415.     sprintf (pipe2, "ram:pipe2_%ld", Uniq);
  1416. }
  1417.  
  1418. main_exit(n)
  1419. {
  1420.     UnLock(CurrentDir(Orig_dir));
  1421.     do_cldres();
  1422.     exit (n);
  1423. }
  1424.  
  1425. docheckbreak()
  1426. {
  1427.     if (checkbreak()) {
  1428.     printf("^C\n");
  1429.     return(1);
  1430.     }
  1431.     return(0);
  1432. }
  1433.  
  1434. \Rogue\Monster\
  1435. else
  1436.   echo "will not over write main.c"
  1437. fi
  1438. if [ `wc -c main.c | awk '{printf $1}'` -ne 2786 ]
  1439. then
  1440. echo `wc -c main.c | awk '{print "Got " $1 ", Expected " 2786}'`
  1441. fi
  1442. if `test ! -s run.c`
  1443. then
  1444. echo "writing run.c"
  1445. cat > run.c << '\Rogue\Monster\'
  1446.  
  1447. /*
  1448.  * RUN.C
  1449.  *
  1450.  *  (C)CopyRight 1987 Matthew Dillon, All rights reserved.
  1451.  *
  1452.  *  RUN handles running of external commands.
  1453.  *
  1454.  */
  1455.  
  1456. #include "shell.h"
  1457. #include "libraries/dos.h"
  1458.  
  1459. extern long *SysRegs;
  1460. extern struct FileLock *Clock;
  1461.  
  1462. do_run(str)
  1463. char *str;
  1464. {
  1465.     int i;
  1466.  
  1467. #ifdef DEBUG
  1468.     if (SDebug) {
  1469.     printf ("RUN: %s '>%s' '<%s' '>>%ld'\n", av[0], (Cin_name)?Cin_name:"&", (Cout_name)?Cout_name:"&", Cout_append);
  1470.     printf ("av[0]=%08lx [1]=%08lx [2]=%08lx\n", av[0],av[1], av[2]);
  1471.     }
  1472. #endif
  1473.     if (fexecv(av[0], av, Cin_name, Cout_name, Cout_append) >= 0) {
  1474.     i = wait();
  1475.     } else {
  1476.     register long lock;
  1477.     register char *copy;
  1478.     char buf[128];
  1479.  
  1480.     mountrequest(0);
  1481.     lock = FindIt(av[0], ".sh", buf);
  1482.     mountrequest(1);
  1483. #ifdef DEBUG
  1484.     if (SDebug)
  1485.         puts("do_run: 1");
  1486. #endif
  1487.     if (lock == NULL) {
  1488.         perror(av[0]);      /*  fixed 26 Mar 88 */
  1489.         return (-1);
  1490.     }
  1491.     av[0] = (char *)-1;
  1492.     av[1] = (char *)lock;
  1493.     copy = malloc(strlen(str)+3);
  1494.     strcpy(copy+2,str);
  1495.     copy[0] = 'x';
  1496.     copy[1] = ' ';
  1497. #ifdef DEBUG
  1498.     if (SDebug)
  1499.         printf ("Do_source: %s\n", copy);
  1500. #endif
  1501.     i = do_source(copy);
  1502.     free(copy);
  1503.     }
  1504.     if (Clock != (struct FileLock *)((struct Process *)FindTask(NULL))->pr_CurrentDir) {
  1505.     Clock = (struct FileLock *)((struct Process *)FindTask(NULL))->pr_CurrentDir;
  1506.     puts("Warning: Current Directory has changed");
  1507.     }
  1508.     return (i);
  1509. }
  1510.  
  1511.  
  1512.  
  1513. \Rogue\Monster\
  1514. else
  1515.   echo "will not over write run.c"
  1516. fi
  1517. if [ `wc -c run.c | awk '{printf $1}'` -ne 1353 ]
  1518. then
  1519. echo `wc -c run.c | awk '{print "Got " $1 ", Expected " 1353}'`
  1520. fi
  1521. if `test ! -s set.c`
  1522. then
  1523. echo "writing set.c"
  1524. cat > set.c << '\Rogue\Monster\'
  1525.  
  1526. /*
  1527.  * SET.C
  1528.  *
  1529.  * (c)1986 Matthew Dillon     9 October 1986
  1530.  *
  1531.  * Handles the variable lists for normal variables, aliases, and labels.
  1532.  */
  1533.  
  1534. #include "shell.h"
  1535. #define MAXLEVELS (3 + MAXSRC)
  1536.  
  1537. struct MASTER {
  1538.     struct MASTER *next;
  1539.     struct MASTER *last;
  1540.     char *name;
  1541.     char *text;
  1542. };
  1543.  
  1544. static struct MASTER *Mbase[MAXLEVELS];
  1545.  
  1546. char *
  1547. set_var(level, name, str)
  1548. short level;
  1549. register char *name, *str;
  1550. {
  1551.     register struct MASTER *base = Mbase[level];
  1552.     register struct MASTER *last;
  1553.     register short len;
  1554.  
  1555.     for (len = 0; isalphanum(name[len]); ++len);
  1556.     while (base != NULL) {
  1557.     if (strlen(base->name) == len && strncmp (name, base->name, len) == 0) {
  1558.         Free (base->text);
  1559.         goto gotit;
  1560.     }
  1561.     last = base;
  1562.     base = base->next;
  1563.     }
  1564.     if (base == Mbase[level]) {
  1565.     base = Mbase[level] = (struct MASTER *)malloc(sizeof(struct MASTER));
  1566.     base->last = NULL;
  1567.     } else {
  1568.     base = (struct MASTER *)malloc (sizeof(struct MASTER));
  1569.     base->last = last;
  1570.     last->next = base;
  1571.     }
  1572.     base->name = malloc (len + 1);
  1573.     bmov (name, base->name, len);
  1574.     base->name[len] = 0;
  1575.     base->next = NULL;
  1576. gotit:
  1577.     base->text = malloc (strlen(str) + 1);
  1578.     strcpy (base->text, str);
  1579.     return (base->text);
  1580. }
  1581.  
  1582. char *
  1583. get_var (level, name)
  1584. short level;
  1585. register char *name;
  1586. {
  1587.     register struct MASTER *base = Mbase[level];
  1588.     register unsigned char *scr;
  1589.     register short len;
  1590.     static char *EnvBuf = NULL;
  1591.     char buf[128];
  1592.     long fh;
  1593.  
  1594.     for (scr = (UBYTE *)name; *scr && *scr != 0x80 && *scr != ' ' && *scr != ';' && *scr != '|'; ++scr);
  1595.     len = scr - name;
  1596.  
  1597.     while (base != NULL) {
  1598.     if (strlen(base->name) == len && strncmp (name, base->name, len) == 0)
  1599.         return (base->text);
  1600.     base = base->next;
  1601.     }
  1602.     mountrequest(0);
  1603.     strcpy(buf, "ENV:");
  1604.     strncat(buf, name, len);
  1605.     buf[4+len] = 0;
  1606.     if (fh = Open(buf, 1005)) {
  1607.     long len = (Seek(fh, 0L, 1), Seek(fh, 0L, 0));
  1608.     if (len < 0)
  1609.         len = 256;
  1610.     if (EnvBuf)
  1611.         free(EnvBuf);
  1612.     if (EnvBuf = malloc(len+1)) {
  1613.         Seek(fh, 0L, -1);
  1614.         len = Read(fh, EnvBuf, len);
  1615.         if (len < 0)
  1616.         len = 0;
  1617.         EnvBuf[len] = 0;
  1618.     }
  1619.     Close(fh);
  1620.     mountrequest(1);
  1621.     return(EnvBuf);
  1622.     }
  1623.     mountrequest(1);
  1624.     return (NULL);
  1625. }
  1626.  
  1627.  
  1628. unset_level(level)
  1629. short level;
  1630. {
  1631.     register struct MASTER *base = Mbase[level];
  1632.     register struct MASTER *next;
  1633.  
  1634.     while (base) {
  1635.     next = base->next;
  1636.     Free (base->name);
  1637.     Free (base->text);
  1638.     Free (base);
  1639.     base = next;
  1640.     }
  1641.     Mbase[level] = NULL;
  1642. }
  1643.  
  1644.  
  1645. unset_var(level, name)
  1646. short level;
  1647. char *name;
  1648. {
  1649.     register struct MASTER *base = Mbase[level];
  1650.     register struct MASTER *last = NULL;
  1651.     register short len;
  1652.  
  1653.     for (len = 0; isalphanum(name[len]); ++len);
  1654.     while (base) {
  1655.     if (strlen(base->name) == len && strncmp (name, base->name, len) == 0) {
  1656.         if (base != Mbase[level])
  1657.         last->next = base->next;
  1658.         else
  1659.         Mbase[level] = base->next;
  1660.         if (base->next != NULL)
  1661.         base->next->last = last;
  1662.         if (base == Mbase[level])
  1663.         Mbase[level] = base->next;
  1664.         Free (base->name);
  1665.         Free (base->text);
  1666.         Free (base);
  1667.         return (1);
  1668.     }
  1669.     last = base;
  1670.     base = base->next;
  1671.     }
  1672.     return (-1);
  1673. }
  1674.  
  1675.  
  1676. do_unset_var(garbage, level)
  1677. short level;
  1678. char *garbage;
  1679. {
  1680.     register short i;
  1681.     register char uu = 0;
  1682.  
  1683.     for (i = 1; i < ac; ++i) {
  1684.     unset_var (level, av[i]);
  1685.     if (*av[i] == '_')
  1686.         uu = '_';
  1687.     }
  1688.     update_under(uu);
  1689.     return (0);
  1690. }
  1691.  
  1692.  
  1693. do_set_var(command, level)
  1694. short level;
  1695. char *command;
  1696. {
  1697.     register struct MASTER *base = Mbase[level];
  1698.     register char *str;
  1699.  
  1700.     if (ac == 1) {
  1701.     while (base) {
  1702.         fhprintf (Cout, "%-10s ", base->name);
  1703.         Oputs (base->text);
  1704.         base = base->next;
  1705.     }
  1706.     return (0);
  1707.     }
  1708.     if (ac == 2) {
  1709.     str = get_var (level, av[1]);
  1710.     if (str) {
  1711.         fhprintf (Cout, "%-10s ", av[1]);
  1712.         Oputs(str);
  1713.     } else {
  1714.         set_var (level, av[1], "");
  1715.     }
  1716.     }
  1717.     if (ac > 2)
  1718.     set_var (level, av[1], next_word (next_word (command)));
  1719.     update_under(*av[1]);
  1720.     return (0);
  1721. }
  1722.  
  1723. static
  1724. update_under(c)
  1725. {
  1726.     register char *str;
  1727.     if (c == '_') {
  1728.     S_histlen = (str = get_var(LEVEL_SET, V_HIST))   ? atoi(str) : 0;
  1729.     S_ignoreeof=(str = get_var(LEVEL_SET, V_IGNOREEOF)) ? 1 : 0;
  1730.     SDebug      = (str = get_var(LEVEL_SET, V_DEBUG))  ? atoi(str) : 0;
  1731.     Verbose   = (get_var(LEVEL_SET, V_VERBOSE)) ? 1 : 0;
  1732.     if (S_histlen < 2)
  1733.         S_histlen = 2;
  1734.     }
  1735. }
  1736.  
  1737.  
  1738.  
  1739. \Rogue\Monster\
  1740. else
  1741.   echo "will not over write set.c"
  1742. fi
  1743. if [ `wc -c set.c | awk '{printf $1}'` -ne 4323 ]
  1744. then
  1745. echo `wc -c set.c | awk '{print "Got " $1 ", Expected " 4323}'`
  1746. fi
  1747. if `test ! -s shell.h`
  1748. then
  1749. echo "writing shell.h"
  1750. cat > shell.h << '\Rogue\Monster\'
  1751.  
  1752. /*
  1753.  * SHELL.H
  1754.  *
  1755.  * (c)1986-1988 Matthew Dillon     18 August 1988
  1756.  *
  1757.  *
  1758.  * SHELL include file.. contains shell parameters and extern's
  1759.  *
  1760.  *
  1761.  */
  1762.  
  1763. #include <local/typedefs.h>
  1764.  
  1765. /*#define FIBF_ARCHIVE      (1<<4)*/
  1766.  
  1767. #define MAXAV        128        /* Max. # arguments         */
  1768. #define MAXSRC        5        /* Max. # of source file levels */
  1769. #define MAXIF        10        /* Max. # of if levels        */
  1770. #define MAXALIAS    20        /* Max. # of alias levels        */
  1771.  
  1772.  
  1773. #define LEVEL_SET    0            /* which variable list to use   */
  1774. #define LEVEL_ALIAS  1
  1775. #define LEVEL_LABEL  2
  1776.  
  1777. #define V_PROMPT     "_prompt"      /* your prompt (ascii command)   */
  1778. #define V_HIST         "_history"     /* set history depth (value)     */
  1779. #define V_HISTNUM    "_histnum"     /* set history numbering var     */
  1780. #define V_DEBUG      "_debug"       /* set debug mode                */
  1781. #define V_VERBOSE    "_verbose"     /* set verbose for source files  */
  1782. #define V_STAT         "_maxerr"      /* worst return value to date    */
  1783. #define V_LASTERR    "_lasterr"     /* return value from last comm.  */
  1784. #define V_CWD         "_cwd"         /* current directory             */
  1785. #define V_EXCEPT     "_except"      /* "nnn;command"                 */
  1786. #define V_PASSED     "_passed"      /* passed arguments to source fle*/
  1787. #define V_PATH         "_path"        /* path prefix,prefix,prefix..   */
  1788. #define V_IGNOREEOF  "_ignoreeof"   /* ignore EOF for interactive tty*/
  1789. #define V_COPYSILENT "_copysilent"  /* silent copy                   */
  1790. #define V_COPYDATE   "_copydate"    /* transport datestamp           */
  1791.  
  1792.  
  1793.         /* EXECOM.C defines */
  1794.  
  1795. #define FL_DOLLAR    0x01  /* One of the following */
  1796. #define FL_BANG      0x02
  1797. #define FL_PERCENT   0x04
  1798. #define FL_QUOTE     0x08
  1799. #define FL_IDOLLAR   0x10  /* Any or all of the following may be set */
  1800. #define FL_EOC         0x20
  1801. #define FL_EOL         0x40
  1802. #define FL_OVERIDE   0x80
  1803. #define FL_WILD      0x100
  1804. #define FL_MASK      (FL_DOLLAR|FL_BANG|FL_PERCENT|FL_QUOTE)
  1805.  
  1806. #define VERSION   "V2.10 (C)Copyright 1986-88 Matthew Dillon, All Rights Reserved, 18 August 1988"
  1807.  
  1808. #ifndef NULL
  1809. #define NULL 0L
  1810. #endif
  1811.  
  1812. #define CHECKBREAK()    docheckbreak()
  1813.  
  1814. struct HIST {
  1815.    struct HIST *next, *prev;     /* doubly linked list */
  1816.    char *line;             /* line in history    */
  1817. };
  1818.  
  1819. struct PERROR {
  1820.    short errnum;         /* Format of global error lookup */
  1821.    char *errstr;
  1822. };
  1823.  
  1824. struct DPTR {             /* Format of directory fetch pointer */
  1825.    struct FileLock *lock;     /* lock on directory    */
  1826.    struct FileInfoBlock *fib;     /* mod'd fib for entry */
  1827. };
  1828.  
  1829. extern struct HIST *H_head, *H_tail;
  1830. extern struct PERROR Perror[];
  1831. extern struct DPTR *dopen();
  1832. extern char *set_var(), *get_var(), *next_word();
  1833. extern char *get_history(), *compile_av();
  1834. extern char *strcpy(), *strcat(), *gets(), *Ogets();
  1835. extern char **expand();
  1836. extern long FindIt();
  1837.  
  1838.  
  1839. extern char *av[];
  1840. extern char *Current;
  1841. extern short H_len, H_tail_base, H_stack;
  1842. extern short E_stack;
  1843. extern short Src_stack, If_stack;
  1844. extern short ac;
  1845. extern short SDebug, Verbose, SDisable, Quit;
  1846. extern long Lastresult;
  1847. extern short Exec_abortline, Exec_ignoreresult;
  1848. extern short S_histlen, S_ignoreeof;
  1849. extern long Uniq;
  1850. extern long Cin, Cout, Cerr, Cout_append;
  1851. extern char *Cin_name, *Cout_name;
  1852. extern char  Cin_type,    Cout_type;  /* these variables are in transition */
  1853. extern char *Pipe1, *Pipe2;
  1854. extern long DResBase;
  1855.  
  1856. extern int  Src_base[MAXSRC];
  1857. extern long Src_pos[MAXSRC];
  1858. extern char If_base[MAXIF];
  1859.  
  1860.  
  1861. \Rogue\Monster\
  1862. else
  1863.   echo "will not over write shell.h"
  1864. fi
  1865. if [ `wc -c shell.h | awk '{printf $1}'` -ne 3410 ]
  1866. then
  1867. echo `wc -c shell.h | awk '{print "Got " $1 ", Expected " 3410}'`
  1868. fi
  1869. if `test ! -s sort.c`
  1870. then
  1871. echo "writing sort.c"
  1872. cat > sort.c << '\Rogue\Monster\'
  1873.  
  1874. /*
  1875.  * SORT.C
  1876.  *
  1877.  * a QuickSort is used for speed, simplicity, and small code size.
  1878.  *
  1879.  */
  1880.  
  1881. extern short QSplit();
  1882.  
  1883.  
  1884. QuickSort(av, n)
  1885. char *av[];
  1886. short n;
  1887. {
  1888.     short b;
  1889.  
  1890.     if (n > 0) {
  1891.     b = QSplit(av, n);
  1892.     QuickSort(av, b);
  1893.     QuickSort(av+b+1, n - b - 1);
  1894.     }
  1895. }
  1896.  
  1897.  
  1898. /*
  1899.  * QSplit called as a second routine so I don't waste stack on QuickSort's
  1900.  * recursivness.
  1901.  */
  1902.  
  1903.  
  1904. short
  1905. QSplit(av, n)
  1906. register char *av[];
  1907. short n;
  1908. {
  1909.     register short i, b;
  1910.     register char *element, *scr;
  1911.  
  1912.     element = av[0];
  1913.     for (b = 0, i = 1; i < n; ++i) {
  1914.     if (strcmp(av[i], element) < 0) {
  1915.         ++b;
  1916.         scr = av[i]; av[i] = av[b]; av[b] = scr;
  1917.     }
  1918.     }
  1919.     scr = av[0]; av[0] = av[b]; av[b] = scr;
  1920.     return (b);
  1921. }
  1922.  
  1923.  
  1924.  
  1925. \Rogue\Monster\
  1926. else
  1927.   echo "will not over write sort.c"
  1928. fi
  1929. if [ `wc -c sort.c | awk '{printf $1}'` -ne 705 ]
  1930. then
  1931. echo `wc -c sort.c | awk '{print "Got " $1 ", Expected " 705}'`
  1932. fi
  1933. if `test ! -s sub.c`
  1934. then
  1935. echo "writing sub.c"
  1936. cat > sub.c << '\Rogue\Monster\'
  1937.  
  1938. /*
  1939.  * SUB.C
  1940.  *
  1941.  * (C)Copyright 1987 Matthew Dillon,    All rights reserved
  1942.  *
  1943.  *      Subroutines used throughout the shell (not very descriptive, am I?)
  1944.  */
  1945.  
  1946.  
  1947. #include <exec/types.h>
  1948. #include <libraries/dos.h>
  1949. #include <libraries/dosextens.h>
  1950. #include "shell.h"
  1951.  
  1952. #define HM_STR 0              /* various HISTORY retrieval modes */
  1953. #define HM_REL 1
  1954. #define HM_ABS 2
  1955.  
  1956. extern struct FileLock *Lock(), *DupLock(), *CurrentDir();
  1957. extern struct FileLock *Clock;
  1958.  
  1959. seterr()
  1960. {
  1961.     char buf[32];
  1962.     int stat;
  1963.  
  1964.     sprintf(buf, "%ld", Lastresult);
  1965.     set_var(LEVEL_SET, V_LASTERR, buf);
  1966.     stat = atoi(get_var(LEVEL_SET, V_STAT));
  1967.     if (stat < Lastresult)
  1968.         stat = Lastresult;
  1969.     sprintf(buf, "%ld", stat);
  1970.     set_var(LEVEL_SET, V_STAT, buf);
  1971. }
  1972.  
  1973.  
  1974. char *
  1975. next_word(str)
  1976. register char *str;
  1977. {
  1978.     while (*str  &&  *str != ' '  &&  *str != 9)
  1979.         ++str;
  1980.     while (*str  && (*str == ' ' || *str == 9))
  1981.         ++str;
  1982.     return (str);
  1983. }
  1984.  
  1985.  
  1986. char *
  1987. compile_av(av, start, end)
  1988. short start, end;
  1989. char **av;
  1990. {
  1991.     char *cstr;
  1992.     short i, len;
  1993.  
  1994.     len = 0;
  1995.     for (i = start; i < end; ++i)
  1996.         len += strlen(av[i]) + 1;
  1997.     cstr = malloc(len + 1);
  1998.     *cstr = '\0';
  1999.     for (i = start; i < end; ++i) {
  2000.         strcat (cstr, av[i]);
  2001.         strcat (cstr, " ");
  2002.     }
  2003.     return (cstr);
  2004. }
  2005.  
  2006. /*
  2007.  * FREE(ptr)   --frees without actually freeing, so the data is still good
  2008.  *               immediately after the free.
  2009.  */
  2010.  
  2011.  
  2012. Free(ptr)
  2013. char *ptr;
  2014. {
  2015.     static char *old_ptr;
  2016.  
  2017.     if (old_ptr)
  2018.         free (old_ptr);
  2019.     old_ptr = ptr;
  2020. }
  2021.  
  2022. /*
  2023.  * Add new string to history (H_head, H_tail, H_len,
  2024.  *  S_histlen
  2025.  */
  2026.  
  2027. add_history(str)
  2028. char *str;
  2029. {
  2030.     register struct HIST *hist;
  2031.  
  2032.     while (H_len > S_histlen)
  2033.         del_history();
  2034.     hist = (struct HIST *)malloc (sizeof(struct HIST));
  2035.     if (H_head == NULL) {
  2036.         H_head = H_tail = hist;
  2037.         hist->next = NULL;
  2038.     } else {
  2039.         hist->next = H_head;
  2040.         H_head->prev = hist;
  2041.         H_head = hist;
  2042.     }
  2043.     hist->prev = NULL;
  2044.     hist->line = malloc (strlen(str) + 1);
  2045.     strcpy (hist->line, str);
  2046.     ++H_len;
  2047. }
  2048.  
  2049. del_history()
  2050. {
  2051.     if (H_tail) {
  2052.         --H_len;
  2053.         ++H_tail_base;
  2054.         free (H_tail->line);
  2055.         if (H_tail->prev) {
  2056.             H_tail = H_tail->prev;
  2057.             free (H_tail->next);
  2058.             H_tail->next = NULL;
  2059.         } else {
  2060.             free (H_tail);
  2061.             H_tail = H_head = NULL;
  2062.         }
  2063.     }
  2064. }
  2065.  
  2066.  
  2067. char *
  2068. last_history_entry()
  2069. {
  2070.     if (H_head)
  2071.         return(H_head->line);
  2072.     return("");
  2073. }
  2074.  
  2075.  
  2076. char *
  2077. get_history(ptr)
  2078. char *ptr;
  2079. {
  2080.     register struct HIST *hist;
  2081.     register short len;
  2082.     short mode = HM_REL;
  2083.     long num  = 1;
  2084.     char *str;
  2085.     char *result = NULL;
  2086.  
  2087.     if (ptr[1] >= '0' && ptr[1] <= '9') {
  2088.         mode = HM_ABS;
  2089.         num  = atoi(&ptr[1]);
  2090.         goto skip;
  2091.     }
  2092.     switch (ptr[1]) {
  2093.     case '!':
  2094.         break;
  2095.     case '-':
  2096.         num += atoi(&ptr[2]);
  2097.         break;
  2098.     default:
  2099.         mode = HM_STR;
  2100.         str  = ptr + 1;
  2101.         break;
  2102.     }
  2103. skip:
  2104.     switch (mode) {
  2105.     case HM_STR:
  2106.         len = strlen(str);
  2107.         for (hist = H_head; hist; hist = hist->next) {
  2108.             if (strncmp(hist->line, str, len) == 0 && *hist->line != '!') {
  2109.                 result = hist->line;
  2110.                 break;
  2111.             }
  2112.         }
  2113.         break;
  2114.     case HM_REL:
  2115.         for (hist = H_head; hist && num--; hist = hist->next);
  2116.         if (hist)
  2117.             result = hist->line;
  2118.         break;
  2119.     case HM_ABS:
  2120.         len = H_tail_base;
  2121.         for (hist = H_tail; hist && len != num; hist = hist->prev, ++len);
  2122.         if (hist)
  2123.             result = hist->line;
  2124.         break;
  2125.     }
  2126.     if (result) {
  2127.         Eputs (result);
  2128.         return(result);
  2129.     }
  2130.     Eputs ("History substitution failed");
  2131.     return ("");
  2132. }
  2133.  
  2134.  
  2135. replace_head(str)
  2136. char *str;
  2137. {
  2138.     if (str == NULL)
  2139.         str = "";
  2140.     if (H_head) {
  2141.         free (H_head->line);
  2142.         H_head->line = malloc (strlen(str)+1);
  2143.         strcpy (H_head->line, str);
  2144.     }
  2145. }
  2146.  
  2147. perror(str)
  2148. char *str;
  2149. {
  2150.     ierror(str, IoErr());
  2151. }
  2152.  
  2153. ierror(str, err)
  2154. register char *str;
  2155. short err;
  2156. {
  2157.     register struct PERROR *per = Perror;
  2158.  
  2159.     if (err) {
  2160.         for (; per->errstr; ++per) {
  2161.             if (per->errnum == err) {
  2162.                 fhprintf (Cerr, "%s%s%s\n",
  2163.                     per->errstr,
  2164.                     (str) ? ": " : "",
  2165.                     (str) ? str : ""
  2166.                 );
  2167.                 return(err);
  2168.             }
  2169.         }
  2170.         fhprintf (Cerr, "Unknown DOS error %ld %s\n", err, (str) ? str : "");
  2171.    }
  2172.    return (err);
  2173. }
  2174.  
  2175. /*
  2176.  * Disk directory routines
  2177.  *
  2178.  * dptr = dopen(name, stat)
  2179.  *    struct DPTR *dptr;
  2180.  *    char *name;
  2181.  *    int *stat;
  2182.  *
  2183.  * dnext(dptr, name, stat)
  2184.  *    struct DPTR *dptr;
  2185.  *    char **name;
  2186.  *    int  *stat;
  2187.  *
  2188.  * dclose(dptr)                  -may be called with NULL without harm
  2189.  *
  2190.  * dopen() returns a struct DPTR, or NULL if the given file does not
  2191.  * exist.  stat will be set to 1 if the file is a directory.  If the
  2192.  * name is "", then the current directory is openned.
  2193.  *
  2194.  * dnext() returns 1 until there are no more entries.  The **name and
  2195.  * *stat are set.  *stat = 1 if the file is a directory.
  2196.  *
  2197.  * dclose() closes a directory channel.
  2198.  *
  2199.  */
  2200.  
  2201. struct DPTR *
  2202. dopen(name, stat)
  2203. char *name;
  2204. register int *stat;
  2205. {
  2206.     register struct DPTR *dp;
  2207.  
  2208.     *stat = 0;
  2209.     dp = (struct DPTR *)malloc(sizeof(struct DPTR));
  2210.     if (*name == '\0')
  2211.         dp->lock = DupLock (Clock);
  2212.     else
  2213.         dp->lock = Lock (name, ACCESS_READ);
  2214.     if (dp->lock == NULL) {
  2215.         free (dp);
  2216.         return (NULL);
  2217.     }
  2218.     dp->fib = (struct FileInfoBlock *)
  2219.             AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC);
  2220.     if (!Examine (dp->lock, dp->fib)) {
  2221.         perror (name);
  2222.         dclose (dp);
  2223.         return (NULL);
  2224.     }
  2225.     if (dp->fib->fib_DirEntryType >= 0)
  2226.         *stat = 1;
  2227.     return (dp);
  2228. }
  2229.  
  2230. dnext(dp, pname, stat)
  2231. register struct DPTR *dp;
  2232. char **pname;
  2233. int *stat;
  2234. {
  2235.     if (dp == NULL)
  2236.         return (0);
  2237.     if (ExNext (dp->lock, dp->fib)) {
  2238.         *stat = (dp->fib->fib_DirEntryType < 0) ? 0 : 1;
  2239.         *pname = dp->fib->fib_FileName;
  2240.         return (1);
  2241.     }
  2242.     return (0);
  2243. }
  2244.  
  2245.  
  2246. dclose(dp)
  2247. register struct DPTR *dp;
  2248. {
  2249.     if (dp == NULL)
  2250.         return (1);
  2251.     if (dp->fib)
  2252.         FreeMem (dp->fib, sizeof(*dp->fib));
  2253.     if (dp->lock)
  2254.         UnLock (dp->lock);
  2255.     free (dp);
  2256.     return (1);
  2257. }
  2258.  
  2259.  
  2260. isdir(file)
  2261. char *file;
  2262. {
  2263.     register struct DPTR *dp;
  2264.     int stat;
  2265.  
  2266.     stat = 0;
  2267.     if (dp = dopen (file, &stat))
  2268.         dclose(dp);
  2269.     return (stat == 1);
  2270. }
  2271.  
  2272.  
  2273. free_expand(av)
  2274. register char **av;
  2275. {
  2276.     register char **base = av;
  2277.  
  2278.     if (av) {
  2279.         while (*av) {
  2280.             free (*av);
  2281.             ++av;
  2282.         }
  2283.         free (base);
  2284.     }
  2285. }
  2286.  
  2287. /*
  2288.  * EXPAND(wild_name, pac)
  2289.  *    wild_name      - char * (example: "df0:*.c")
  2290.  *    pac            - int  *  will be set to # of arguments.
  2291.  *
  2292.  * Standalone, except in requires Clock to point to the Current-Directory
  2293.  * lock.
  2294.  */
  2295.  
  2296.  
  2297. char **
  2298. expand(base, pac)
  2299. char *base;
  2300. int *pac;
  2301. {
  2302.     register char *ptr;
  2303.     char **eav = (char **)malloc (sizeof(char *));
  2304.     short eleft, eac;
  2305.     char *name;
  2306.     char *bname, *ename, *tail;
  2307.     int stat, scr;
  2308.     register struct DPTR *dp;
  2309.  
  2310.     *pac = eleft = eac = 0;
  2311.  
  2312.     base = strcpy(malloc(strlen(base)+1), base);
  2313.     for (ptr = base; *ptr && *ptr != '?' && *ptr != '*'; ++ptr);
  2314.     for (; ptr >= base && !(*ptr == '/' || *ptr == ':'); --ptr);
  2315.     if (ptr < base) {
  2316.         bname = strcpy (malloc(1), "");
  2317.     } else {
  2318.         scr = ptr[1];
  2319.         ptr[1] = '\0';
  2320.         bname = strcpy (malloc(strlen(base)+1), base);
  2321.         ptr[1] = scr;
  2322.     }
  2323.     ename = ptr + 1;
  2324.     for (ptr = ename; *ptr && *ptr != '/'; ++ptr);
  2325.     scr = *ptr;
  2326.     *ptr = '\0';
  2327.     tail = (scr) ? ptr + 1 : NULL;
  2328.  
  2329.     if ((dp = dopen (bname, &stat)) == NULL  ||  stat == 0) {
  2330.         free (bname);
  2331.         free (base);
  2332.         free (eav);
  2333.         Eputs ("Could not open directory");
  2334.         return (NULL);
  2335.     }
  2336.     while (dnext (dp, &name, &stat)) {
  2337.         if (compare_ok(ename, name)) {
  2338.             if (tail) {
  2339.                 int alt_ac;
  2340.                 char *search, **alt_av, **scrav;
  2341.                 struct FileLock *lock;
  2342.  
  2343.                 if (!stat)           /* expect more dirs, but this not a dir */
  2344.                     continue;
  2345.                 lock = CurrentDir (Clock = dp->lock);
  2346.                 search = malloc(strlen(name)+strlen(tail)+2);
  2347.                 strcpy (search, name);
  2348.                 strcat (search, "/");
  2349.                 strcat (search, tail);
  2350.                 scrav = alt_av = expand (search, &alt_ac);
  2351.                 CurrentDir (Clock = lock);
  2352.                 if (scrav) {
  2353.                     while (*scrav) {
  2354.                         if (eleft < 2) {
  2355.                             char **scrav = (char **)malloc(sizeof(char *) * (eac + 10));
  2356.                             bmov (eav, scrav, (eac + 1) << 2);
  2357.                             free (eav);
  2358.                             eav = scrav;
  2359.                             eleft = 10;
  2360.                         }
  2361.                         eav[eac] = malloc(strlen(bname)+strlen(*scrav)+1);
  2362.                         strcpy(eav[eac], bname);
  2363.                         strcat(eav[eac], *scrav);
  2364.                         free (*scrav);
  2365.                         ++scrav;
  2366.                         --eleft, ++eac;
  2367.                     }
  2368.                     free (alt_av);
  2369.                 }
  2370.             } else {
  2371.                 if (eleft < 2) {
  2372.                     char **scrav = (char **)malloc(sizeof(char *) * (eac + 10));
  2373.                     bmov (eav, scrav, (eac + 1) << 2);
  2374.                     free (eav);
  2375.                     eav = scrav;
  2376.                     eleft = 10;
  2377.                 }
  2378.                 eav[eac] = malloc (strlen(bname)+strlen(name)+1);
  2379.                 eav[eac] = strcpy(eav[eac], bname);
  2380.                 strcat(eav[eac], name);
  2381.                 --eleft, ++eac;
  2382.             }
  2383.         }
  2384.     }
  2385.     dclose (dp);
  2386.     *pac = eac;
  2387.     eav[eac] = NULL;
  2388.     free (bname);
  2389.     free (base);
  2390.     if (eac)
  2391.         return (eav);
  2392.     free (eav);
  2393.     return (NULL);
  2394. }
  2395.  
  2396. /*
  2397.  * Compare a wild card name with a normal name
  2398.  */
  2399.  
  2400. #define MAXB   8
  2401.  
  2402. compare_ok(wild, name)
  2403. char *wild, *name;
  2404. {
  2405.     register char *w = wild;
  2406.     register char *n = name;
  2407.     char *back[MAXB][2];
  2408.     register char s1, s2;
  2409.     register short bi = 0;
  2410.  
  2411.     while (*n || *w) {
  2412.         switch (*w) {
  2413.         case '*':
  2414.             if (bi == MAXB) {
  2415.                 Eputs ("Too many levels of '*'");
  2416.                 return (0);
  2417.             }
  2418.             back[bi][0] = w;
  2419.             back[bi][1] = n;
  2420.             ++bi;
  2421.             ++w;
  2422.             continue;
  2423. goback:
  2424.             --bi;
  2425.             while (bi >= 0 && *back[bi][1] == '\0')
  2426.                 --bi;
  2427.             if (bi < 0)
  2428.                 return (0);
  2429.             w = back[bi][0] + 1;
  2430.             n = ++back[bi][1];
  2431.             ++bi;
  2432.             continue;
  2433.         case '?':
  2434.             if (!*n) {
  2435.                 if (bi)
  2436.                     goto goback;
  2437.                 return (0);
  2438.             }
  2439.             break;
  2440.         default:
  2441.             s1 = (*n >= 'A' && *n <= 'Z') ? *n - 'A' + 'a' : *n;
  2442.             s2 = (*w >= 'A' && *w <= 'Z') ? *w - 'A' + 'a' : *w;
  2443.             if (s1 != s2) {
  2444.                 if (bi)
  2445.                     goto goback;
  2446.                 return (0);
  2447.             }
  2448.             break;
  2449.         }
  2450.         if (*n)  ++n;
  2451.         if (*w)  ++w;
  2452.     }
  2453.     return (1);
  2454. }
  2455.  
  2456.  
  2457. Oputs(str)
  2458. char *str;
  2459. {
  2460.     Write (Cout, str, strlen(str));
  2461.     Write (Cout, "\n", 1);
  2462. }
  2463.  
  2464. Eputs(str)
  2465. char *str;
  2466. {
  2467.     Write (Cerr, str, strlen(str));
  2468.     Write (Cerr, "\n", 1);
  2469. }
  2470.  
  2471. char *
  2472. Ogets(str)
  2473. char *str;
  2474. {
  2475.     register int i = 0;
  2476.  
  2477.     while (Read(Cin, str + i, 1) == 1) {
  2478.         if (str[i] == '\n') {
  2479.             str[i] = 0;
  2480.             return (str);
  2481.         }
  2482.         if (++i == 255) {
  2483.             str[i] = 0;
  2484.             return (str);
  2485.         }
  2486.     }
  2487.     return (NULL);
  2488. }
  2489.  
  2490.  
  2491.  
  2492. \Rogue\Monster\
  2493. else
  2494.   echo "will not over write sub.c"
  2495. fi
  2496. if [ `wc -c sub.c | awk '{printf $1}'` -ne 11900 ]
  2497. then
  2498. echo `wc -c sub.c | awk '{print "Got " $1 ", Expected " 11900}'`
  2499. fi
  2500. if `test ! -s tags`
  2501. then
  2502. echo "writing tags"
  2503. cat > tags << '\Rogue\Monster\'
  2504. do_sleep comm1.c /^do_sleep(
  2505. do_number comm1.c /^do_number(
  2506. do_cat comm1.c /^do_cat(
  2507. do_comment comm1.c /^do_comment(
  2508. do_dir comm1.c /^do_dir(
  2509. disp_entry comm1.c /^disp_entry(
  2510. do_quit comm1.c /^do_quit(
  2511. do_echo comm1.c /^do_echo(
  2512. do_source comm1.c /^do_source(
  2513. do_cd comm1.c /^do_cd(
  2514. attempt_cd comm1.c /^attempt_cd(
  2515. rmlast comm1.c /^rmlast(
  2516. do_mkdir comm1.c /^do_mkdir(
  2517. do_mv comm1.c /^do_mv(
  2518. do_rm comm1.c /^do_rm(
  2519. rmdir comm1.c /^rmdir(
  2520. do_history comm1.c /^do_history(
  2521. do_mem comm1.c /^do_mem(
  2522. do_foreach comm1.c /^do_foreach(
  2523. do_forever comm1.c /^do_forever(
  2524. do_abortline comm2.c /^do_abortline(
  2525. do_return comm2.c /^do_return(
  2526. do_strhead comm2.c /^do_strhead(
  2527. do_strtail comm2.c /^do_strtail(
  2528. do_if comm2.c /^do_if(
  2529. do_label comm2.c /^do_label(
  2530. do_goto comm2.c /^do_goto(
  2531. do_inc comm2.c /^do_inc(
  2532. do_input comm2.c /^do_input(
  2533. do_ver comm2.c /^do_ver(
  2534. do_cp comm2.c /^do_cp(
  2535. copydir comm2.c /^copydir(
  2536. copyfile comm2.c /^copyfile(
  2537. do_shellstat comm2.c /^do_shellstat(
  2538. do_printenv comm2.c /^do_printenv(
  2539. do_setenv comm2.c /^do_setenv(
  2540. do_unsetenv comm2.c /^do_unsetenv(
  2541. exec_command execom.c /^exec_command(
  2542. isalphanum execom.c /^isalphanum(
  2543. preformat execom.c /^preformat(
  2544. fcomm execom.c /^fcomm(
  2545. exarg execom.c /^exarg(
  2546. mpush_base execom.c /^mpush_base(
  2547. mpush execom.c /^mpush(
  2548. mpop_tobase execom.c /^mpop_tobase(
  2549. format_insert_string execom.c /^format_insert_string(
  2550. find_command execom.c /^find_command(
  2551. do_help execom.c /^do_help(
  2552. wait fexec1.c /^wait(
  2553. fexecv fexec1.c /^fexecv(
  2554. LoadIt fexec1.c /^LoadIt(
  2555. FindIt fexec1.c /^FindIt(
  2556. isfile fexec1.c /^isfile(
  2557. hat_replace hat.c /^hat_replace(
  2558. main main.c /^main(
  2559. init_vars main.c /^init_vars(
  2560. init main.c /^init(
  2561. main_exit main.c /^main_exit(
  2562. docheckbreak main.c /^docheckbreak(
  2563. do_run run.c /^do_run(
  2564. set_var set.c /^set_var(
  2565. get_var set.c /^get_var (
  2566. unset_level set.c /^unset_level(
  2567. unset_var set.c /^unset_var(
  2568. do_unset_var set.c /^do_unset_var(
  2569. do_set_var set.c /^do_set_var(
  2570. update_under set.c /^update_under(
  2571. QuickSort sort.c /^QuickSort(
  2572. QSplit sort.c /^QSplit(
  2573. seterr sub.c /^seterr(
  2574. next_word sub.c /^next_word(
  2575. compile_av sub.c /^compile_av(
  2576. Free sub.c /^Free(
  2577. add_history sub.c /^add_history(
  2578. del_history sub.c /^del_history(
  2579. last_history_entry sub.c /^last_history_entry(
  2580. get_history sub.c /^get_history(
  2581. replace_head sub.c /^replace_head(
  2582. perror sub.c /^perror(
  2583. ierror sub.c /^ierror(
  2584. dopen sub.c /^dopen(
  2585. dnext sub.c /^dnext(
  2586. dclose sub.c /^dclose(
  2587. isdir sub.c /^isdir(
  2588. free_expand sub.c /^free_expand(
  2589. expand sub.c /^expand(
  2590. compare_ok sub.c /^compare_ok(
  2591. Oputs sub.c /^Oputs(
  2592. Eputs sub.c /^Eputs(
  2593. Ogets sub.c /^Ogets(
  2594. \Rogue\Monster\
  2595. else
  2596.   echo "will not over write tags"
  2597. fi
  2598. if [ `wc -c tags | awk '{printf $1}'` -ne 2590 ]
  2599. then
  2600. echo `wc -c tags | awk '{print "Got " $1 ", Expected " 2590}'`
  2601. fi
  2602. echo "Finished archive 1 of 2"
  2603. # if you want to concatenate archives, remove anything after this line
  2604. exit
  2605. -- 
  2606. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  2607. Have five nice days.
  2608.